/**
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to marcus@lateralminds.com.au so I can send you a copy immediately.
 *
 * @copyright  Copyright (c) 2008 Lateral Minds (http://www.lateralminds.com.au)
 * @version    $Id$
 * @license    New BSD License
 */

package com.lateralminds.alfresco.caas.services;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.XPath;
import org.jaxen.dom4j.Dom4jXPath;

/**
 * A keyword extractor that uses the Yahoo! REST service to extract
 * keywords from a content string. 
 * 
 * @author Marcus Nyeholt 
 *
 */
public class YahooKeywordExtractor implements KeywordExtractor
{
    private static final Log logger = LogFactory.getLog(YahooKeywordExtractor.class);
    
    /*
     * (non-Javadoc)
     * @see com.lateralminds.alfresco.caas.services.KeywordExtractor#getKeywords(org.alfresco.service.cmr.repository.NodeRef)
     */
    public List<String> getKeywords(NodeRef nodeRef) throws Throwable
    {
        // Get the content of the nodeRef as text (using a transformation)
        String content = "";
        ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
        ContentWriter writer = contentService.getTempWriter();
        writer.setMimetype("text/plain");
        contentService.transform(reader, writer);
        content = writer.getReader().getContentString();
        
        return getKeywords(content, reader.getEncoding());
    }

    /*
     * (non-Javadoc)
     * @see com.lateralminds.alfresco.caas.services.KeywordExtractor#getKeywords(java.lang.String)
     */
    public List<String> getKeywords(String content, String encoding) throws Throwable
    {
        List<String> keywords = new ArrayList<String>();
        if (content == null || content.length() <= 10) {
            return keywords;
        }
        try {
            HttpClient httpClient = new HttpClient();
            PostMethod postMethod = new PostMethod(this.yahooUrl);
            
            postMethod.addRequestHeader("Content-Type",
                    "application/x-www-form-urlencoded; charset="+encoding);
            
            NameValuePair[] data = {
                    new NameValuePair("appid", this.yahooAppId),
                    new NameValuePair("context", content),
                  };
            postMethod.addParameters(data);
            
            int responseCode = httpClient.executeMethod(postMethod);
            if (responseCode != 200) {
                throw new Exception("Invalid response code: 403");
            }
            
            String xml = postMethod.getResponseBodyAsString();
            
            Document domDoc = DocumentHelper.parseText(xml);
            
            HashMap<String, String> map = new HashMap<String, String>();
            Element node = domDoc.getRootElement();
            Namespace ns = node.getNamespace();
            map.put( "yui", ns.getURI());
            XPath xpath = new Dom4jXPath( "//yui:Result");
            xpath.setNamespaceContext(new SimpleNamespaceContext( map));
            
            List<Element> nodes = xpath.selectNodes(domDoc);
            
            for (Element n : nodes) {
                keywords.add(n.getTextTrim());
            }
        } catch (Throwable e) {
            logger.error("Failed extracting keywords: "+e.getMessage(), e);
            throw e;
        }
        return keywords;
    }

    private ContentService contentService;
    private String yahooUrl;
    private String yahooAppId;

    public void setContentService(ContentService contentService)
    {
        this.contentService = contentService;
    }

    public void setYahooUrl(String yahooUrl)
    {
        this.yahooUrl = yahooUrl;
    }

    public void setYahooAppId(String yahooAppId)
    {
        this.yahooAppId = yahooAppId;
    }
}
